/***********************************************************************************
 * 文件名： mbre.c
 * 作者： 刘言
 * 版本： 1.0
 * 说明：
 * 		MBRE(ModBusRtuExt) 1.1 通信协议（网络层）的实现。
 *      单缓存覆盖机制：发送方每次发送数据都会复写缓存，所以发送方必须确保接收方已经处理了上
 *  一包数据才能发送下一包数据。
 * 修改记录：
 * 	2021/2/1: 初版。 刘言。
 *  2021/4/12: 增加加密通信功能。 刘言
 *  2021/4/14: 增加主机功能，主从可任意切换。
 *  2021/11/02: RETURN数据包结果使用-1(0XFF)表示数据未发完。
***********************************************************************************/
#include "mbre.h"
#include "polsys.h"

// 预处理


// 属性

static idata mbre_callback_t mCall = NULL;

#if (_MBRE_ROLE == 2)
static pdata mbre_role_t mRole = MBRE_ROLE_SLAVE;
#endif

#if (_MBRE_ROLE != 1) // 以下为主机专用属性
static pdata u8 mTargetDevice = 0;
#endif


// 内部函数声明

static void ReturnCmd(mbre_cmd_t cmd);

// 对外接口函数

IN_LINE void Mbre_Init()
{
    MbreLink_Init();
}

IN_LINE void Mbre_SetCb(mbre_callback_t callback_func)
{
    mCall = callback_func;
}

#if (_MBRE_ROLE == 2)

FORCE_IN_LINE void Mbre_SetRole(mbre_role_t role)
{
    mRole = role;
}

#endif

#if (_MBRE_ROLE != 1) // 以下为主机专用函数

void Mbre_FindSlave(const u8 *uid, u8 uid_length)
{
    ALIGN(4) u8 buff[18];    // 数据量较小直接使用局部变量

    if(uid_length > 16)uid_length = 16;
    ((mbre_data_t *)buff)->Id = MBRE_SID_OP_ID;
    ((mbre_data_t *)buff)->Cmd = MBRE_CMD_FIND;
    memcpy(buff + 2, uid, uid_length);
    MbreLink_SendPkg(18, buff);
}

void Mbre_ModifyId(const u8 *uid, u8 uid_length, u8 new_id)
{
    ALIGN(4) u8 buff[22];

    if(uid_length > 16)uid_length = 16;
    ((mbre_data_t *)buff)->Id = MBRE_SID_OP_ID;
    ((mbre_data_t *)buff)->Cmd = MBRE_CMD_MODIFY_ID;
    memcpy(buff + 2, uid, uid_length);
    buff[18] = new_id;
    MbreLink_SendPkg(22, buff);
}

FORCE_IN_LINE void Mbre_SetTargetDevice(u8 SlaveID)
{
    mTargetDevice = SlaveID;
}

void Mbre_Read(u32 addr, u16 length)
{
    ALIGN(4) u8 buff[8];

    ((mbre_data_t *)buff)->Id = mTargetDevice;
    ((mbre_data_t *)buff)->Cmd = MBRE_CMD_READ;
    Mbre_FormatReadParam(((mbre_data_t *)buff)->Param)->Addr = addr;
    Mbre_FormatReadParam(((mbre_data_t *)buff)->Param)->ReadLength = length;
    MbreLink_SendPkg(8, buff);
}

bool Mbre_Write(u32 addr, u8 *dat, u16 length)
{
    ALIGN(4) u8 buff[_MBRE_MAX_TX_DATA_LEN];

    if (length > _MBRE_MAX_TX_DATA_LEN - 8)return false;

    ((mbre_data_t *)buff)->Id = mTargetDevice;
    ((mbre_data_t *)buff)->Cmd = MBRE_CMD_WRITE;
    Mbre_FormatWriteParam(((mbre_data_t *)buff)->Param)->Addr = addr;
    Mbre_FormatWriteParam(((mbre_data_t *)buff)->Param)->WriteLength = length;
    memcpy(Mbre_FormatWriteParam(((mbre_data_t *)buff)->Param)->WData, dat, length);
    MbreLink_SendPkg(8 + length, buff);
    return true;
}

void Mbre_Action(u8 act_code)
{
    ALIGN(4) u8 buff[4];

    ((mbre_data_t *)buff)->Id = mTargetDevice;
    ((mbre_data_t *)buff)->Cmd = MBRE_CMD_ACTION;
    buff[2] = act_code;
    MbreLink_SendPkg(4, buff);
}

#endif

#if (_MBRE_ROLE != 0) // 以下为从机专用函数

void Mbre_ReturnRead(const u8 *dat, u16 length)
{
    ALIGN(4) u8 buff[_MBRE_MAX_TX_DATA_LEN];

    if (length > _MBRE_MAX_TX_DATA_LEN - 4)length = _MBRE_MAX_TX_DATA_LEN - 4;

    ((mbre_data_t *)buff)->Id = _Mbre_GetLocalID();
    ((mbre_data_t *)buff)->Cmd = MBRE_CMD_READ;
    *((u16 *)(&buff[2])) = length;
    memcpy(buff + 4, dat, length);
    MbreLink_SendPkg(length + 4, buff);
}

void Mbre_ReturnWrite(u32 addr, u16 length)
{
    ALIGN(4) u8 buff[8];

    ((mbre_data_t *)buff)->Id = _Mbre_GetLocalID();
    ((mbre_data_t *)buff)->Cmd = MBRE_CMD_WRITE;
    *((u16 *)(&buff[4])) = addr;
    *((u16 *)(&buff[6])) = length;
    MbreLink_SendPkg(8, buff);
}

void Mbre_ReturnAction(bool succeed)
{
    ALIGN(4) u8 buff[4];

    ((mbre_data_t *)buff)->Id = _Mbre_GetLocalID();
    ((mbre_data_t *)buff)->Cmd = MBRE_CMD_ACTION;
    buff[2] = (u8)succeed;
    MbreLink_SendPkg(4, buff);
}

#endif

// 由外部调用（一般是MbreLink）来通知 Mbre 有新的链路层事件。
void _Mbre_EvLinkEvent(mbre_event_t e)
{
    switch (e)
    {
    case MBRE_EV_RECEIVED_PKG:
    {
        mbre_data_t *buff = MbreLink_GetReceiveData();
        u16 len = MbreLink_GetLength();
#if (_MBRE_ROLE == 2)
        if (mRole == MBRE_ROLE_HOST) // 目前是主机
#endif
#if (_MBRE_ROLE != 1) // 不是仅从机，需要主机代码
        {
            switch(buff->Cmd)
            {
            case MBRE_CMD_FIND:         // 从机返回了FIND命令
            case MBRE_CMD_MODIFY_ID:    // 从机返回了MODIFY_ID命令
                mTargetDevice = buff->Id;
                mCall(MBRE_EV_RECEIVED_PKG); // 上报事件：收到一包数据
                break;
            default:
                if (buff->Id == mTargetDevice) // 是目标设备回应的数据包
                {
                    mCall(MBRE_EV_RECEIVED_PKG); // 上报事件：收到一包数据
                }
                else
                {
                    mCall(MBRE_EV_BUS_ERROR);
                }
                break;
            }
        }
#endif
#if (_MBRE_ROLE == 2)
        else // 目前是从机
#endif
#if (_MBRE_ROLE != 0) // 不是仅主机，需要从机代码
        {
            switch(buff->Cmd)
            {
            case MBRE_CMD_FIND:         // 主机发送了FIND命令
                if(memcmp(_Mbre_GetUid(), buff->Param, _Mbre_GetUidLength()) == 0)
                {
                    ReturnCmd(MBRE_CMD_FIND);
                }
                break;
            case MBRE_CMD_MODIFY_ID:    // 主机发送了MODIFY_ID命令
                if(memcmp(_Mbre_GetUid(), buff->Param, _Mbre_GetUidLength()) == 0)
                {
                    _Mbre_SetLocalID(buff->Param[16]);
                    ReturnCmd(MBRE_CMD_MODIFY_ID);
                }
                break;
            default:
                if (buff->Id == _Mbre_GetLocalID()) // 是发给本机的数据包
                {
                    mCall(MBRE_EV_RECEIVED_PKG); // 上报事件：收到一包数据
                }
                break;
            }
        }
#endif
        break;
    }
    default:
        mCall(e); // 直接向上传递事件
        break;
    }
}

// 内部函数

#if (_MBRE_ROLE != 0) // 以下为从机专用函数

/**
 * 返回无参数命令
*/
static void ReturnCmd(mbre_cmd_t cmd)
{
    u8 buff[2];

    ((mbre_data_t *)buff)->Id = _Mbre_GetLocalID();
    ((mbre_data_t *)buff)->Cmd = cmd;
    MbreLink_SendPkg(2, buff);
}

#endif
